package com.guli.eduService.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.guli.commonUtils.vo.CourseVo;
import com.guli.eduService.entity.EduCourse;
import com.guli.eduService.entity.EduCourseDescription;
import com.guli.eduService.entity.EduSubject;
import com.guli.eduService.entity.EduTeacher;
import com.guli.eduService.entity.vo.*;
import com.guli.eduService.mapper.EduCourseMapper;
import com.guli.eduService.service.EduCourseService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guli.serviceBase.Entity.GuliExcepiton;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 课程 服务实现类
 * </p>
 *
 * @author zxc
 * @since 2023-04-03
 */
@Service
public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {

    // 注入EduCourseDescriptionServiceImpl类，用于保存 课程简介信息到课程简介表中;
    @Autowired
    private EduCourseDescriptionServiceImpl courseDescriptionService;

    @Autowired
    private EduSubjectServiceImpl subjectService;

    @Autowired
    private EduVideoServiceImpl videoService;

    @Autowired
    private EduChapterServiceImpl chapterService;

    @Autowired
    private EduTeacherServiceImpl teacherService;

    // 条件查询，分页获取符合条件的库存数据;
    @Override
    public void conditionQueryCourseInfo(QueryCourseFormInfo queryCourseFormInfo, Page<EduCourse> coursePage) {
        // 创建QueryWrapper对象，用来封装queryCourseFormInfo中所定义查询条件;
        QueryWrapper<EduCourse> queryWrapper = new QueryWrapper<>();
        // 1.前端页面所传递过来的查询对象为空 ：
        if(queryWrapper == null){
            // page方法 ：
            // （1）首先，根据所封装的查询条件对象queryWrapper，来查询出所有符合条件的课程数据;
            // （2）其次，将所查询到所有数据，都赋予给Page对象;
            // 分页功能的实现，是Page对象内部实现的;
            // 需要注意的是，Page对象中存储了所有查询到符合条件的课程信息;
            this.page(coursePage , queryWrapper);
            return;
        }
        // 2.前端页面所传递过来的查询对象不为空;
        // 获取QueryCourseFormInfo对象中，所封装的所有查询条件 && 将其封装到QueryWrapper对象中;
        String title = queryCourseFormInfo.getTitle();
        String teacherId = queryCourseFormInfo.getTeacherId();
        String subjectParentId = queryCourseFormInfo.getSubjectParentId();
        String subjectId = queryCourseFormInfo.getSubjectId();
        // 需要注意的是，所封装查询条件QueryWrapper所需要满足的条件
        // 　＝＝＝＞［数据库中字段，指定值］
        if(!StringUtils.isEmpty(title)){
            queryWrapper.like("title" , title);
        }
        if(!StringUtils.isEmpty(teacherId)){
            queryWrapper.eq("teacher_id" , teacherId);
        }
        if(!StringUtils.isEmpty(subjectParentId)){
            queryWrapper.eq("subject_parent_id" , subjectParentId);
        }
        if(!StringUtils.isEmpty(subjectId)){
            queryWrapper.eq("subject_id" , subjectId);
        }
        this.page(coursePage , queryWrapper);
    }

    // 具体实现类，即用来实现接口中所定义的添加课程基本信息方法;
    @Override
    public String addCourseInfo(SaveCourseFormInfo courseFormInfo) {
        // 1.添加数据到 edu-course（课程表中）
        EduCourse eduCourse = new EduCourse();

        // 需要去获取 当前课程专业的父级ID
        // 写法一 ：
        // （1）封装查询条件
//        QueryWrapper<EduSubject> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("id" , courseFormInfo.getSubjectId());
//        // （2）在edu-subject中，查询 当前id为当前课程专业id的记录
//        EduSubject eduSubject = eduSubjectService.getOne(queryWrapper);

        // 写法二 ：
        // EduSubject eduSubject1 = eduSubjectService.getById(courseFormInfo.getSubjectId());

        // （3）前端页面所传递过来的表单数据，封装到eduCourse实体类中;
        BeanUtils.copyProperties(courseFormInfo , eduCourse);
        eduCourse.setStatus(EduCourse.COURSE_DRAFT);
//        eduCourse.setSubjectParentId(eduSubject.getParentId());
        // （4）调用添加课程基本信息的方法
        boolean isCourse = this.save(eduCourse);
        // （5）判断是否添加课程成功
        if(!isCourse){
            throw new GuliExcepiton(20005 , "课程基本信息，保存失败！！！");
        }

        String courseId = eduCourse.getId();
        // 2.添加数据到 edu-course-description（课程简介表中）
        EduCourseDescription eduCourseDescription = new EduCourseDescription();
        // 注意 ：获取上述保存到 表edu-course中的课程id;
        eduCourseDescription.setId(courseId);
        eduCourseDescription.setDescription(courseFormInfo.getDescription());
        boolean isCourseDescription = courseDescriptionService.save(eduCourseDescription);
        if(!isCourseDescription){
            throw new GuliExcepiton(20004 , "课程简介信息，保存失败！！！");
        }

        return courseId;
    }

    // 具体实现，根据id，来获取当前课程的基本信息;
    @Override
    public SaveCourseFormInfo getCourseVOInfo(String courseId) {
        // 1.获取edu-course数据表中的信息
        EduCourse courseInfo = this.getById(courseId);
        // 2.获取edu-courseDescription数据表中的信息
        EduCourseDescription courseDescription = courseDescriptionService.getById(courseId);
        // 3.构建 课程表单对象，同时将其返回给前端页面;
        SaveCourseFormInfo courseFormInfo = new SaveCourseFormInfo();
        // 修复bug，删除当前课程的简介信息后，由于根据该课程id，查询不到对应的课程简介信息，也就无法将其赋值给courseFormInfo;
        // 即，当前课程所对应的简介信息很有可能为NULL;
        if(courseDescription != null){
            BeanUtils.copyProperties(courseDescription , courseFormInfo);
        }
        // 若是课程基本信息为NULL的话，则代表了当前课程是不存在的;
        try {
            BeanUtils.copyProperties(courseInfo , courseFormInfo);
        } catch (Exception e) {
            e.printStackTrace();
            throw new GuliExcepiton(20001 , "该课程不存在！！！");
        }
        return courseFormInfo;
    }

    // 具体实现 对于指定课程基本信息进行修改;
    @Override
    public String updateCourseInfo(SaveCourseFormInfo courseFormInfo) {
        // 前端所传递的表单数据，转化到EduCourse实体类中;
        EduCourse eduCourse = new EduCourse();
        BeanUtils.copyProperties(courseFormInfo , eduCourse);
//        EduSubject subject = eduSubjectService.getById(eduCourse.getSubjectId());
//        eduCourse.setSubjectParentId(subject.getParentId());
        boolean isCourse = this.updateById(eduCourse);
        if(!isCourse){
            throw new GuliExcepiton(20002 , "课程基本信息，修改失败！！！");
        }

        // 前端所传递的表单数据，转化到EduCourseDescription实体类中;
        EduCourseDescription courseDescription = new EduCourseDescription();
        BeanUtils.copyProperties(courseFormInfo , courseDescription);
        // 修复bug，当前课程对应的课程简介不存在的话，编辑课程简介信息时，由于数据库中不存在该课程简介信息，所以调用update方法，会报错;
        // （1）根据课程id，查询数据库中的课程简介信息：
        EduCourseDescription descriptionInfo = courseDescriptionService.getById(courseFormInfo.getId());
        // （2）若是在数据库中该课程简介信息不存在的话，则将前端所修改的课程简介信息，直接添加到edu-courseDescription表中;
        boolean isCourseDescription;
        if(descriptionInfo == null){
            isCourseDescription = courseDescriptionService.save(courseDescription);
        }
        // （3）若是在数据库中该课程简介信息存在的话，则选择直接对于该课程简介信息进行修改即可;
        else {
            isCourseDescription = courseDescriptionService.updateById(courseDescription);
        }
        if(!isCourseDescription){
            throw new GuliExcepiton(20003 , "课程简介信息信息，修改失败！！！");
        }
        // 即，返回当前课程的id;
        return courseFormInfo.getId();
    }

    // 具体实现 根据课程id，联合多个数据库表中数据，来查询指定课程的详细信息;
    @Override
    public PublishedCourseVO queryPulishedCourseInfo(String courseId) {
        PublishedCourseVO publishedCourseInfo = baseMapper.queryCourseInfo(courseId);
        if(publishedCourseInfo == null){
            throw new GuliExcepiton(20001 , "该课程不存在！！！");
        }
        return publishedCourseInfo;
    }

    @Override
    public boolean updatePublishCourseInfo(String courseId) {
        // 1.查询当前课程的状态信息;
        EduCourse course = this.getById(courseId);
        // 若是当前课程状态为已经发布的话，则提示已经发布过;
        if(course.getStatus().equals(EduCourse.COURSE_NORMAL)){
            return false;
        }
        boolean flag = baseMapper.updatePublishedCourseInfo(EduCourse.COURSE_NORMAL, courseId);
        if(!flag){
            throw new GuliExcepiton(20006 , "发布课程失败！！！");
        }
        return flag;
    }

    //  根据课程id，删除课程的所有信息（如何实现事务性，即删除操作要么全部成功，要么全部失败;）
    @Override
    @Transactional(rollbackFor = Exception.class) // 即，抛出任何异常，都会进行回滚数据，从而保证数据前后的一致性;
    public boolean deleteAllCourseInfo(String courseId) {
        // 1.删除当前课程id，所对应的课程简介信息;
        // 由于课程简介信息中，课程id就是其主键;
        boolean descriptionIsDeleted = courseDescriptionService.removeById(courseId);
        if(!descriptionIsDeleted){
            throw new GuliExcepiton(20010 , "课程简介信息删除失败！！！");
        }
        // 2.删除当前课程id，所对应的章节信息;
        boolean chapterIsDeleted = chapterService.removeByCourseId(courseId);
        if(!chapterIsDeleted){
            throw new GuliExcepiton(20011 , "课程章节信息删除失败！！！");
        }
        // 3.删除当前课程id，所对应的课程课时信息;
        boolean videoIsDeleted = videoService.removeByCourseId(courseId);
        if(!videoIsDeleted){
            throw new GuliExcepiton(20012 , "课程课时信息删除失败！！！");
        }
        // 4.删除当前课程id，所对应的课程基本信息
        boolean courseIsDeleted = this.removeById(courseId);
        if(!courseIsDeleted){
            throw new GuliExcepiton(20013 , "课程基本信息删除失败！！！");
        }
        // 若是上述所有内容的删除都未抛出异常的话，则代表该课程的所有信息都被删除成功;
        return true;
    }

    @Override
    @Cacheable(value = "course" , key = "'indexCourseList'")
    public List<EduCourse> queryByCourseNum(String courseNum) {
        // 1.封装课程的查询规则
        QueryWrapper<EduCourse> courseQueryWrapper = new QueryWrapper<>();
        courseQueryWrapper.orderByDesc("view_count");
        // 用于拼接sql语句
        courseQueryWrapper.last("limit " + courseNum);
        List<EduCourse> courseInfo = this.list(courseQueryWrapper);
        return courseInfo;
    }

    @Override
    public Map<String, Object> listCourseFrontInfo(Page<EduCourse> pageParam, CourseQueryVO courseQuery) {
        QueryWrapper<EduCourse> queryWrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(courseQuery.getTitle())) {
            queryWrapper.like("title", courseQuery.getTitle());
        }

        if (!StringUtils.isEmpty(courseQuery.getTeacherId())) {
            queryWrapper.eq("teacher_id", courseQuery.getTeacherId());
        }

        if (!StringUtils.isEmpty(courseQuery.getSubjectParentId())) {
            queryWrapper.eq("subject_parent_id", courseQuery.getSubjectParentId());
        }

        if (!StringUtils.isEmpty(courseQuery.getSubjectId())) {
            queryWrapper.eq("subject_id", courseQuery.getSubjectId());
        }

        if (!StringUtils.isEmpty(courseQuery.getBuyCountSort())) {
            queryWrapper.orderByDesc("buy_count");
        }

        if (!StringUtils.isEmpty(courseQuery.getGmtCreateSort())) {
            queryWrapper.orderByDesc("gmt_create");
        }

        if (!StringUtils.isEmpty(courseQuery.getPriceSort())) {
            queryWrapper.orderByDesc("price");
        }

        baseMapper.selectPage(pageParam, queryWrapper);

        List<EduCourse> records = pageParam.getRecords();
        long current = pageParam.getCurrent();
        long pages = pageParam.getPages();
        long size = pageParam.getSize();
        long total = pageParam.getTotal();
        boolean hasNext = pageParam.hasNext();
        boolean hasPrevious = pageParam.hasPrevious();

        Map<String, Object> map = new HashMap<String, Object>();
        map.put("records", records);
        map.put("current", current);
        map.put("pages", pages);
        map.put("size", size);
        map.put("total", total);
        map.put("hasNext", hasNext);
        map.put("hasPrevious", hasPrevious);

        return map;
    }

    @Override
    public CourseDetailsVO queryCourseDetails(String courseId) {
        // 1.由于用户查看了当前课程，所以当前页面的浏览量需要加一;
        this.updateCourseViewCount(courseId);
        // 2.再根据课程id，去查询前台页面所需要展示的课程数据信息;
        CourseDetailsVO courseDetails = baseMapper.queryCourseDetails(courseId);
        return courseDetails;
    }

    @Override
    public void updateCourseViewCount(String courseId) {
        // 1.首先，根据课程id，查询到指定的课程信息;
        EduCourse course = this.getById(courseId);
        // 2.其次，对于所查询到的课程信息，浏览量进行加一;
        Long viewCount = course.getViewCount();
        course.setViewCount(viewCount + 1);
        // 3.最后，将修改后的课程信息同步到数据库中;
        this.updateById(course);
    }

    @Override
    public CourseVo queryBasicCourseInfo(String courseId) {
        // 1.根据课程id，查询对应课程信息;
        EduCourse course = this.getById(courseId);
        // 2.根据讲师id，查询对应讲师信息
        EduTeacher teacher = teacherService.getById(course.getTeacherId());
        // 3.将所查询到的课程信息和讲师信息，封装到CourseVO类中;
        CourseVo basicCourseInfo = new CourseVo();

        basicCourseInfo.setTeacherName(teacher.getName());
        basicCourseInfo.setCourseId(course.getId());
        basicCourseInfo.setCourseCover(course.getCover());
        basicCourseInfo.setCourseTitle(course.getTitle());
        basicCourseInfo.setTotalFee(course.getPrice());

        return basicCourseInfo;
    }

}
